﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.Rendering;

namespace RainEngine.Effects
{
    /// <summary>
    /// 对绘制天空盒的SkyBox.fx的封装。
    /// </summary>
    public class SkyBoxEffect : Effect
    {              
        // Effect参数        
        EffectParameter worldViewProjParam;
        EffectParameter cubeTextureParam;
        EffectParameter clipPlaneParam;
        EffectParameter clipPlaneEnabledParam;

        // 字段
        Matrix world = Matrix.Identity;
        Matrix view = Matrix.Identity;
        Matrix projection = Matrix.Identity;
        Vector3 eyePosition=Vector3 .Zero ;        
        bool clipPlaneEnabled = false;       

        EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;

        /// <summary>
        /// 获取或设置世界矩阵。世界矩阵改变时会影响effect的WorldViewProj参数
        /// </summary>
        public Matrix World
        {
            get { return world; }
            set
            {
                world = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置视矩阵,视矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix View
        {
            get { return view; }
            set
            {
                view = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置投影矩阵,,投影矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix Projection
        {
            get { return projection; }
            set
            {
                projection = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置相机位置,相机位置改变时会影响effect的WorldViewProj。
        /// </summary>
        public Vector3 EyePosition
        {
            get { return eyePosition; }
            set
            {
                eyePosition = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置天空盒使用的立方纹理
        /// </summary>
        public TextureCube CubeTexture
        {
            get { return cubeTextureParam.GetValueTextureCube(); }
            set { cubeTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置剪裁平面，将这个值设置为Vector.Zero就关闭剪裁
        /// </summary>
        public Vector4 ClipPlane
        {
            get { return clipPlaneParam.GetValueVector4(); }
            set 
            {
                if (value == Vector4.Zero)
                    clipPlaneEnabled = false;
                else
                    clipPlaneEnabled = true;
                clipPlaneEnabledParam.SetValue(clipPlaneEnabled);
                clipPlaneParam.SetValue (value);  
            }
        }

        /// <summary>
        /// 使用默认参数创建一个新SkyBoxEffect对象。
        /// </summary>
        public SkyBoxEffect(GraphicsDevice device)
            : base(device, Resource.SkyBoxEffectBin)
        {
            CacheEffectParameters(null); 
        }

        /// <summary>
        /// 通过从一个已经存在的对象中复制参数创建一个新SkyBoxEffect对象。
        /// </summary>
        protected SkyBoxEffect(SkyBoxEffect cloneSource)
            : base(cloneSource)
        {
            CacheEffectParameters(cloneSource);

            world = cloneSource.world;
            view = cloneSource.view;
            projection = cloneSource.projection;
            eyePosition =cloneSource .eyePosition ;
            clipPlaneEnabled = cloneSource.clipPlaneEnabled;
        }


        /// <summary>
        /// 创建一个当前SkyBoxEffect对象的副本。
        /// </summary>
        public override Effect Clone()
        {
            return new SkyBoxEffect(this);
        }

        /// <summary>
        /// 缓存effect的参数。
        /// </summary>
        void CacheEffectParameters(SkyBoxEffect cloneSource)
        {
            worldViewProjParam = Parameters["WorldViewProj"];
            cubeTextureParam = Parameters["CubeTexture"];
            clipPlaneParam = Parameters["ClipPlane"];
            clipPlaneEnabledParam = Parameters["ClipPlaneEnabled"];
        }


        /// <summary>
        /// 在施加effect前根据需要重新计算effect参数。
        /// </summary>
        protected override void OnApply()
        {
            // 重新计算WorldViewProj组合矩阵
            if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
            {
                world = Matrix.CreateTranslation (eyePosition);
                
                Matrix worldView=Matrix.Multiply(world, view);
                Matrix worldViewProj=Matrix.Multiply(worldView, projection);
                worldViewProjParam.SetValue(worldViewProj);

                dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
            }
        }
    }
}